JavaScript 是一门弱类型语言,从不需要类型转换。对象继承关系变得无关紧要。对于一个对象来说重要的时它能够做什么,而不是它从哪里来。
阅读《javascript语言精粹》笔记!
伪类
js
的原型存在许多的矛盾,它不能直接让对象从另外一个对象继承,反而出现了一个多余的简介曾:通过构造函数来产生对象。
当函数对象创建的时候,function
构造器产生的函数对象会运行类似这样的代码:
function Person() {};
Person.prototype = {
constructor: this;
};
新的函数汇赋予一个prototype
的值,因为js
语言没有提供一个方法去确定哪个函数式打算来做构造器的,所以每个函数都会有一个prototype
的对象。而关心的是prototype
对象,而不是constructor
。
但采用构造器调用模式,即是使用了new
前缀去调用一个函数时,函数执行的方式会改变。
Function.method('new', function(){
var that = Object.create(this.prototype),
other = this.apply(this, arguments);
return (typeof other === 'object' && other) || that;
});
- 先创建一个新的对象,它继承自构造器函数的原型对象
- 调用构造器函数,绑定
this
到新的对象上面 - 如果它的放回值不是一个对象的话,就放回哪个新对象
来定义两个构造器并扩展它的原型:
function Person(name) {
this.name = name;
};
Person.prototype.sayName = function(){
alert(this.name);
};
function Cat(name) {
this.name = name;
};
可以让另一个伪类去继承Person
,通过定义它的constructor
函数并且替换了它prototype
为一个Person
的实例来实现:
Cat.prototype = new Person;
然后来给Cat
的prototype
上添加一个方法:
Cat.prototype.sayHello = function(){
alert('Hello');
};
最后实例化Cat
并且调用它的方法:
var cat = new Cat('john');
cat.sayName(); // john
cat.sayHello(); // Hello
最后还有修改Cat
的construction
指向:
Cat.prototype.constructor = Cat;
可以通过使用method
方法来定义一个inherits
方法来实现伪类的继承:
Function.method('inherits', function(Parent){
this.prototype = new Parent;
return this;
});
伪类模式继承的问题:
- 没有私有环境,所有属性都是公开的。无法访问
super
(父类)方法。 - 如果在调用构造器函数时候忘记调用
new
操作符,那么this
将不会绑定到新的对象上,而是全局window
上。 - “伪类”的形式可以给不收悉
js
的程序员便利,但它也隐藏了该语言的真实本质。借鉴类的表示法可能误导程序员去编写过于深入与复杂的层次结构。 -
construction
的指向错误。
对象说明符
有的时候,构造器可能要接受一大串的参数,而且还要记住参数的顺序是很困难滴,在这种情况下,编写构造器的时候让它接受一个对象说明符,可能会更加的方便。
function Person(name, age, sex, scholl, add) {};
参数改成对象说明符的形式:
function Person({
name: 'john',
age: 16,
sex: 'man',
scholl: 'zhyz',
add: 'zhuhai'
});
好处:现在能够多个参数按照任意顺序去排列,如果构造器会聪明的使用默认值,一些参数可以被忽略掉,并且代码更加容易的阅读。
原型
在一个纯粹的原型继模式中,我们会摒弃类,转而专注于对象。
基于原型的继承先对基于类的继承在概念上更加简单:一个对象可以继承以旧的对象。
用对象字面量来创建一个对象:
var Person = {
name: 'john',
sayName: function(){
alert(this.name);
},
sayHello: function(){
alert('Hello');
}
};
有了想要的对象后,就可以利用Object.create
方法来构造出更多的实例:
var nPerson = Object.create(Person);
nPerson.sayName(); // john
这是一种差异化继承。通过定制一个新的对象,我们指明它与所基于的基本对象的区别。
下面的例子演示了如何使用Object.create
来实现类式继承。这是一个单继承。(来自MDN)
//Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); //call super constructor.
}
Rectangle.prototype = Object.create(Shape.prototype);
var rect = new Rectangle();
rect instanceof Rectangle //true.
rect instanceof Shape //true.
rect.move(1, 1); //Outputs, "Shape moved."
函数化
大部分所看到的继承模式的一个弱点就是没办法去保护隐私。对象的属性都是可见的。没有办法得到私有的变量和函数。
var consturctor = function(spec, my){
var that, // 其他的私有实例变量
my = my || {};
// 把共享的变量和函数添加到 my 中
// 给 that = 一个新的对象
// 添加给 that 的特权方法
// 最后把 that 对象返回
return that;
};
- 创建一个对象。
- 定义私有实例的变量和方法。
- 给这个新的对象扩充方法,这些方法拥有特权去访问参数。
- 返回那个对象。
spec
对象包含构造器需要构造一个新的实例的所有信息。spec
的可能会被复制到私有变量中,或者被其他函数改变,或者方法可以在需要的时候访问spec
的信息。
声明该对象私有的实例变量的方法。通过简单地声明变量就可以做到了。构造器的变量和内部函数变成了该实例的私有成员。
my
对象是一个为继承链中的构构造器提供的秘密共享的容器。通过给my
对象添加共享秘密成员:
my.member = value;
然后构造一个新的对象并且把它赋值给that
。接着扩充that
,加入组成该对象接口的特权方法。可以分配一个新函数成为that
的成员方法,然后再把它分配给that
:
var methodical = function(){ ... };
that.methodical = methodical;
分两步去定义methodical
的好处就是,如果其他方法想要调用methodical
,它们可以直接调用methodical()
而是不是that.methodical()
。如果实例遭到破坏或修改,调用methodical
照样会继续工作,因为它们私有的methodical
不会该实例被修改的影响。
最后把that
返回。
函数化模式有很大的灵活性。它相比伪类模式不仅带来的工作更少,还让我们得到更好的封装和信息隐藏,以及访问父类方法的能力。
如果对象的所有状态都是私有的,那么该对象就成为一个“防伪”对象。该对象的属性可以被替换或删除,但该对象的完整性不会受到伤害。
部件
从一套部件中吧对象组装出来。例如,构造一个给任何对象添加简单事件处理特性的函数。他会给对象添加一个on
方法、一个fire
方法和一个私有的事件注册表对象。
用这种方法,一个构造器函数可以从一套部件中把对象组装出来。js
的弱类型在这里就是一个巨大的优势,因为无需花费精力去了解对象在类型系统中的集成关系。
var eventuality = function(that){
var registry = {};
that.fire = function(e){
var arry, func, handler, i,
type = typeof e === 'string' ? e : e.type;
if (registry.hasOwnProperty(type)) {
array = registry[type];
for (i = 0; i < array.length; i += 1) {
handler = array[i];
func = handler.method;
if (typeof func === 'string') {
func = this[func];
}
func.apply(this, handler.parameters || [e]);
}
}
return this;
};
that.on = function(type, method, parameters){
var handler = {
method;: method,
parameters: parameters
};
if (registry.hasOwnProperty(type)) {
registry[type].push(handler);
} else {
registry[type] = [handler];
}
return that;
};
return that;
};
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。